import { list } from '../services/file'
import { exec } from 'child_process'
import * as path from 'path'
import * as fs from 'fs'
import { debounce } from 'lodash'
import { Context } from '../type'
import { pubsub, emitter } from '../index'
const pathWatcherMap: Map<string, fs.FSWatcher> = new Map()
const pathChannelMap: Map<string, Set<string>> = new Map()
const channelPathMap: Map<string, string> = new Map()

setTimeout(() => {
  emitter.on('channelExit', (channel) => {
    const path = channelPathMap.get(channel)
    const channels = pathChannelMap.get(path)
    const watcher = pathWatcherMap.get(path)
    if (path) {
      channels.delete(channel)
      if (channels.size === 0) {
        pathChannelMap.delete(path)
        if (watcher) {
          watcher.close()
        }
        pathWatcherMap.delete(path)
      } else {
        pathChannelMap.set(path, channels)
      }
      channelPathMap.delete(channel)
    }
  })
}, 0)
export default class FileController {
  static list(path: string) {
    return list(path)
  }
  static path(paths: string[]) {
    return path.resolve(...paths)
  }
  static watch(path: string, { channel }: Context) {
    const oldPath = channelPathMap.get(channel)
    if (oldPath && oldPath !== path) {
      const channels = pathChannelMap.get(oldPath)
      channels.delete(channel)
      pathChannelMap.set(oldPath, channels)
    }
    channelPathMap.set(channel, path)
    const channels = pathChannelMap.get(path) || new Set()
    channels.add(channel)
    pathChannelMap.set(path, channels)
    let watch = pathWatcherMap.get(path)
    if (!watch) {
      watch = fs.watch(path, {
        persistent: false,
      })
      const handleChange = debounce(async (eventType, filename) => {
        const sendList = Array.from(channels)
        const result = await FileController.list(path)
        for (const sendChannel of sendList) {
          pubsub.publish(sendChannel, {
            list: result,
          })
        }
      }, 100)
      watch.on('change', handleChange)
      pathWatcherMap.set(path, watch)
    }
  }
  static openFile(path: string) {
    exec(path)
    return 0
  }
}
